package models

import (
	"strings"
	"sync"
	"time"

	"github.com/shxsun/klog"
)

const TIME_FORMAT = "2006/01/02 15:04:05"

var (
	defaultChain = NewChain()
	chainExists  = make(map[string]bool)
	chainLock    = sync.RWMutex{}
	logs         = klog.DevLog
)

func initChain() (err error) {
	rs := make([]Record, 0)
	err = Engine.Cols("path").Distinct("path").Find(&rs)
	if err != nil {
		return
	}
	for _, r := range rs {
		paths := strings.Split(r.Path, "/")
		length := len(paths)
		defaultChain.Add(paths[length-1], paths[:length-1]...)
		chainExists[r.Path] = true
	}
	return
}

type Record struct {
	Id    int64  `xorm:"id pk not null autoincr"`
	Time  int64  `xorm:"unique(u)"`
	Path  string `xorm:"unique(u)"`
	Value int
}

type Description struct {
	Path     string `json:"path" xorm:"unique"`
	UnitName string `json:"unitname"`
	Low      int    `json:"low"`
	High     int    `json:"high"`
}

func UpdateDescription(desc Description) (err error) {
	affecd, err := Engine.Insert(desc)
	if err != nil || affecd == 0 {
		affecd, err = Engine.
			Where("`path`=?", desc.Path).
			Update(desc)
		if err != nil || affecd != 1 {
			return err
		}
	}
	return nil
}

func GetDescription(path string) (desc Description, err error) {
	_, err = Engine.Where("`path`=?", path).Get(&desc)
	return
}

func AddRecord(path string, value int) (err error) {
	logs.Debug(path, value)
	r := new(Record)
	r.Path = path
	r.Value = value
	r.Time = time.Now().UnixNano()
	_, err = Engine.InsertOne(r)

	chainLock.RLock()
	defer chainLock.RUnlock()
	if err == nil && !chainExists[r.Path] {
		go func() {
			chainLock.Lock()
			defer chainLock.Unlock()
			chainExists[r.Path] = true
			paths := strings.Split(r.Path, "/")
			length := len(paths)
			defaultChain.Add(paths[length-1], paths[:length-1]...)
		}()
	}
	return
}

// TODO: change to GetRecords
func GetRecords(path string, from int64) (data [][2]interface{}, err error) {
	rs := make([]Record, 0)
	err = Engine.Where("`path`=? AND `time`>?", path, from).Desc("time").Limit(5000).Find(&rs)
	if err != nil {
		return
	}
	data = make([][2]interface{}, 0)
	for i := len(rs) - 1; i >= 0; i-- {
		r := &rs[i]
		data = append(data, [2]interface{}{r.Time, r.Value})
	}
	return
}

func GetChain() (chain *Chain) {
	return defaultChain
}
